<?php

class Common_Process_Locker
{

    private $_pid       = null;
    private $_name      = null;

    private $_lockFile  = null;

    private $_logger    = null;

    public function __construct()
    {
    }

    public function getName()
    {
        return $this->_name;
    }

    public function lock($lockFile, $lockName)
    {
        
        if (file_exists($lockFile)) {

            $pid = $this->getPidFromLockFile($lockFile);

            if ($this->_isRunning()) {
                $this->_log('Process [' . $this->getName(). '] is already running with process ID [' . $pid . '].');
                return false;
            } else {
                $this->_log('Process [' . $this->getName(). '] with process ID [' . $pid . '] died abruptly.');
            }
        }

        $this->_lockFile = $lockFile;
        $this->_name = $lockName;
        $this->_pid = getmypid();

        $this->savePidIntoLockFile($lockFile, $this->_pid);

        $this->_log('Lock acquired for process [' . $this->getName(). '] with process ID [' . $this->_pid . '].');
        $this->_log('Lock saved to file [' . $lockFile . '].', Zend_Log::DEBUG);

        return $this->_pid;
    }

    public function unlock()
    {
        if ($this->isLocked()) {
            if (file_exists($this->_lockFile)) {
                @unlink($this->_lockFile);
            }

            $this->_log('Releasing lock for process [' . $this->getName(). '] with process ID [' . $this->_pid . '].');
        }
        
        return true;
    }

    public function isLocked()
    {
        return !empty($this->_lockFile);
    }

    public function getLockFile()
    {
        return $this->_lockFile;
    }

    private function getPidFromLockFile($lockFile)
    {
        $pid = null;
        if (file_exists($lockFile)) {
            $contents = file_get_contents($lockFile);
            $data = json_decode($contents, true);
            $pid = isset($data['pid']) ? $data['pid'] : null;
        }

        return $pid;
    }

    private function savePidIntoLockFile($lockFile, $pid)
    {
        $fileExists = file_exists($lockFile);
        file_put_contents($lockFile, json_encode(array('pid' => $pid, 'data' => array())));
        if (!$fileExists) {
            chmod($lockFile, 0777);
        }
    }

    private function _isRunning()
    {
        $pids = explode(PHP_EOL, `ps -e | awk '{print $1}'`);

        if (!empty($this->_pid) && in_array($this->_pid, $pids)) {
            return true;
        }

        return false;
    }

    public function setLogger(Zend_Log $logger)
    {
        $this->_logger = $logger;
    }

    public function hasLogger()
    {
        return ($this->_logger instanceof Zend_Log);
    }

    public function getLogger()
    {
        return $this->_logger;
    }

    private function _log($message, $priority = Zend_Log::INFO)
    {
        if ($this->hasLogger()) {
            $this->getLogger()->log($message, $priority);
        }
    }
}